package com.ihg.hiex.admin.service.account.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.collections.MapUtils;
import org.springframework.stereotype.Service;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.persistence.annotation.Dao;
import com.demo2do.core.utils.CollectionUtils;
import com.ihg.hiex.admin.dao.account.AccountDao;
import com.ihg.hiex.admin.dao.account.DelegateDao;
import com.ihg.hiex.admin.dao.session.EmailTemplateDao;
import com.ihg.hiex.admin.dao.session.SessionParticipatorDao;
import com.ihg.hiex.admin.entity.search.CoachingProgressSearch;
import com.ihg.hiex.admin.entity.upload.OnlineAccount;
import com.ihg.hiex.admin.service.DataServiceImpl;
import com.ihg.hiex.admin.service.account.DelegateService;
import com.ihg.hiex.entity.data.notice.EmailTemplate;
import com.ihg.hiex.entity.session.Session;
import com.ihg.hiex.entity.session.SessionNotification;
import com.ihg.hiex.entity.session.participator.SessionParticipator;
import com.ihg.hiex.entity.user.Account;
import com.ihg.hiex.entity.user.Administrator;
import com.ihg.hiex.entity.user.Delegate;
import com.ihg.hiex.entity.user.DelegateAttribute;
import com.ihg.hiex.entity.user.Role;

/**
 * 
 * @author ZEAL
 *        
 */
@Service("delegateService")
public class DelegateServiceImpl extends DataServiceImpl<Delegate> implements DelegateService {
    
    @Dao
    private DelegateDao            delegateDao;
                                   
    @Dao
    private SessionParticipatorDao sessionParticipatorDao;
    
    @Dao
    private EmailTemplateDao emailTemplateDao;
    
    @Dao
    private AccountDao accountDao;
                                   
    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ihg.hiex.assessment.service.account.DelegateService#list(java.util.
     * List)
     */
    public List<Delegate> list(List<Long> ids) {
        return delegateDao.list(ids);
    }
    
    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ihg.hiex.assessment.service.account.DelegateService#list(com.ihg.hiex.
     * entity.session.Session)
     */
    @SuppressWarnings("unchecked")
    public List<Delegate> list(Session session) {
        
        // 1. list delegate_id of session
        List<SessionParticipator> participators = sessionParticipatorDao.list(session);
        List<Long> delegateIds = CollectionUtils.extractPropertyList(participators, "delegateId");
        
        // 2. list delegate by delegate_ids
        return delegateDao.list(delegateIds);
        
    }
    
    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ihg.hiex.admin.service.account.DelegateService#listAttribute(com.wtw.
     * ihg.entity.user.Delegate)
     */
    public Map<String, DelegateAttribute> listAttribute(Delegate delegate) {
        List<DelegateAttribute> attributes = delegateDao.listAttribute(delegate);
        return CollectionUtils.constructMapValue(attributes, "name");
    }
    
    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ihg.hiex.admin.service.account.DelegateService#listAttribute(java.util
     * .List)
     */
    public Map<String, Map<String, DelegateAttribute>> listAttribute(List<Delegate> delegates) {
        if(!delegates.isEmpty()) {
            List<DelegateAttribute> attributes = delegateDao.listAttribute(delegates);
            
            Map<String, List<DelegateAttribute>> attribute = CollectionUtils.constructMapValues(attributes, "delegate.id");
            Map<String, Map<String, DelegateAttribute>> result = new HashMap<String, Map<String, DelegateAttribute>>();
            for (Entry<String, List<DelegateAttribute>> attr : attribute.entrySet()) {
                Map<String, DelegateAttribute> resultItem = CollectionUtils.constructMapValue(attr.getValue(), "name");
                result.put(attr.getKey(), resultItem);
            }
            return result;
        }
        return null;
    }
    
    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ihg.hiex.admin.service.account.DelegateService#list(java.lang.Long)
     */
    public List<Delegate> list(Long coachId) {
        return delegateDao.list("delegate-coach", coachId.toString());
    }
    
    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ihg.hiex.admin.service.account.DelegateService#search(com.ihg.hiex.
     * admin.entity.search.CoachingProgressSearch)
     */
    @SuppressWarnings("unchecked")
    public List<Delegate> search(CoachingProgressSearch search) {
        return genericDaoSupport.searchForList(search.buildSentenceTemplate(), search.buildParameters());
    }
    
    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ihg.hiex.admin.service.account.DelegateService#edit(com.ihg.hiex.entity
     * .user.Delegate)
     */
    public void edit(Delegate delegate) {
        
        // 1. edit account
        Account account = delegate.getAccount();
        account.edit(delegate.getTelephone());
        genericDaoSupport.update(account.initialize());
        
        // 2. edit delegate
        genericDaoSupport.update(delegate.edit());
        
    }
    
    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ihg.hiex.admin.service.account.DelegateService#disable(com.ihg.hiex.
     * entity.user.Delegate)
     */
    public void disable(Delegate delegate) {
        
        // 1. disable account
        Account account = delegate.getAccount();
        genericDaoSupport.update(account.disable());
        
        // 2. disable delegate
        genericDaoSupport.update(delegate.disable());
    }
    
    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ihg.hiex.admin.service.account.DelegateService#uploadOnlineAccount(
     * java.util.List)
     */
    public void uploadOnlineAccount(List<OnlineAccount> onlineAccounts) {
        
        // 若excel文件内容为空，抛出异常
        if ( onlineAccounts.isEmpty() ) {
            throw new BusinessException("online account is empty");
        }
        
        // 插入在线账号
        for (OnlineAccount onlineAccount : onlineAccounts) {
            Delegate delegate = delegateDao.load(onlineAccount.getEmail());
            if ( delegate != null ) {
                DelegateAttribute waveAccount = new DelegateAttribute(delegate, "wave-account", onlineAccount.getWaveAccount());
                genericDaoSupport.save(waveAccount);
                
                DelegateAttribute swiftAccount = new DelegateAttribute(delegate, "swift-account", onlineAccount.getSwiftAccount());
                genericDaoSupport.save(swiftAccount);
                DelegateAttribute swiftPassword = new DelegateAttribute(delegate, "swift-password", onlineAccount.getSwiftPassword());
                genericDaoSupport.save(swiftPassword);
            }
        }
        
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.account.DelegateService#addDelegateAttribute(com.ihg.hiex.entity.user.Delegate, java.lang.String, java.lang.String, com.ihg.hiex.entity.session.Session)
     */
    public void addDelegateAttribute(Delegate delegate, String name, String value, Session session) {
        
        DelegateAttribute delegateAttribute = new DelegateAttribute(delegate, name, value);
        genericDaoSupport.save(delegateAttribute);
        
        // create session notification
        EmailTemplate emailTemplate = emailTemplateDao.load("coachBind");
        SessionNotification notification = new SessionNotification(session, emailTemplate, null, delegate.getId());
        genericDaoSupport.save(notification);
        
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.account.DelegateService#editDelegateAttribute(com.ihg.hiex.entity.user.DelegateAttribute, java.lang.String, com.ihg.hiex.entity.session.Session)
     */
    public void editDelegateAttribute(DelegateAttribute attribute, String value, Session session) {
        
        genericDaoSupport.update(attribute.edit(value));
        
        // create session notification
        EmailTemplate emailTemplate = emailTemplateDao.load("bindCoach");
        SessionNotification notification = new SessionNotification(session, emailTemplate, new Date(), attribute.getDelegate().getId());
        genericDaoSupport.save(notification);
        
    }
    
    /* (non-Javadoc)
     * @see com.ihg.hiex.admin.service.account.DelegateService#bindCoach(com.ihg.hiex.entity.user.Administrator, com.ihg.hiex.entity.user.Delegate, com.ihg.hiex.entity.session.Session)
     */
    public void bindCoach(Administrator admin, Delegate delegate, Session session) {
        
        Account account = null;
        String email = admin.getEmail().toLowerCase().replace(" ", "");
        Account existAccount = accountDao.loadByEmail(admin.getEmail().toLowerCase());
        if(existAccount != null) {
            if(!existAccount.hasAuthority(Role.COACH.toString())) {
                genericDaoSupport.update(existAccount.addAuthority(Role.COACH.toString()));
            }
            account = existAccount;
        } else {
            account = new Account(admin.getEmail(), Role.COACH.toString(), admin.getTelephone());
            genericDaoSupport.save(account.initialize());
        }
        
        // save admin and account first
        genericDaoSupport.save(admin.initialize(account));
        
        // save or update delgate attribute
        String coachId = admin.getId().toString();
        Map<String, DelegateAttribute> delegateAttributes = this.listAttribute(delegate);
        if(MapUtils.isNotEmpty(delegateAttributes) && delegateAttributes.get("delegate-coach") != null) {
          this.editDelegateAttribute(delegateAttributes.get("delegate-coach"), coachId, session);
        } else {
          this.addDelegateAttribute(delegate, "delegate-coach", coachId, session);
        }
        
    }
    
}
